/*
 * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */

package java.util;

import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.io.Serializable;

/**
 * An object that maps keys to values.  A map cannot contain duplicate keys;
 * each key can map to at most one value.
 *
 * <p>This interface takes the place of the <tt>Dictionary</tt> class, which
 * was a totally abstract class rather than an interface.
 *
 * <p>The <tt>Map</tt> interface provides three <i>collection views</i>, which
 * allow a map's contents to be viewed as a set of keys, collection of values,
 * or set of key-value mappings.  The <i>order</i> of a map is defined as
 * the order in which the iterators on the map's collection views return their
 * elements.  Some map implementations, like the <tt>TreeMap</tt> class, make
 * specific guarantees as to their order; others, like the <tt>HashMap</tt>
 * class, do not.
 *
 * <p>Note: great care must be exercised if mutable objects are used as map
 * keys.  The behavior of a map is not specified if the value of an object is
 * changed in a manner that affects <tt>equals</tt> comparisons while the
 * object is a key in the map.  A special case of this prohibition is that it
 * is not permissible for a map to contain itself as a key.  While it is
 * permissible for a map to contain itself as a value, extreme caution is
 * advised: the <tt>equals</tt> and <tt>hashCode</tt> methods are no longer
 * well defined on such a map.
 *
 * <p>All general-purpose map implementation classes should provide two
 * "standard" constructors: a void (no arguments) constructor which creates an
 * empty map, and a constructor with a single argument of type <tt>Map</tt>,
 * which creates a new map with the same key-value mappings as its argument.
 * In effect, the latter constructor allows the user to copy any map,
 * producing an equivalent map of the desired class.  There is no way to
 * enforce this recommendation (as interfaces cannot contain constructors) but
 * all of the general-purpose map implementations in the JDK comply.
 *
 * <p>The "destructive" methods contained in this interface, that is, the
 * methods that modify the map on which they operate, are specified to throw
 * <tt>UnsupportedOperationException</tt> if this map does not support the
 * operation.  If this is the case, these methods may, but are not required
 * to, throw an <tt>UnsupportedOperationException</tt> if the invocation would
 * have no effect on the map.  For example, invoking the {@link #putAll(Map)}
 * method on an unmodifiable map may, but is not required to, throw the
 * exception if the map whose mappings are to be "superimposed" is empty.
 *
 * <p>Some map implementations have restrictions on the keys and values they
 * may contain.  For example, some implementations prohibit null keys and
 * values, and some have restrictions on the types of their keys.  Attempting
 * to insert an ineligible key or value throws an unchecked exception,
 * typically <tt>NullPointerException</tt> or <tt>ClassCastException</tt>.
 * Attempting to query the presence of an ineligible key or value may throw an
 * exception, or it may simply return false; some implementations will exhibit
 * the former behavior and some will exhibit the latter.  More generally,
 * attempting an operation on an ineligible key or value whose completion
 * would not result in the insertion of an ineligible element into the map may
 * throw an exception or it may succeed, at the option of the implementation.
 * Such exceptions are marked as "optional" in the specification for this
 * interface.
 *
 * <p>Many methods in Collections Framework interfaces are defined
 * in terms of the {@link Object#equals(Object) equals} method.  For
 * example, the specification for the {@link #containsKey(Object)
 * containsKey(Object key)} method says: "returns <tt>true</tt> if and
 * only if this map contains a mapping for a key <tt>k</tt> such that
 * <tt>(key==null ? k==null : key.equals(k))</tt>." This specification should
 * <i>not</i> be construed to imply that invoking <tt>Map.containsKey</tt>
 * with a non-null argument <tt>key</tt> will cause <tt>key.equals(k)</tt> to
 * be invoked for any key <tt>k</tt>.  Implementations are free to
 * implement optimizations whereby the <tt>equals</tt> invocation is avoided,
 * for example, by first comparing the hash codes of the two keys.  (The
 * {@link Object#hashCode()} specification guarantees that two objects with
 * unequal hash codes cannot be equal.)  More generally, implementations of
 * the various Collections Framework interfaces are free to take advantage of
 * the specified behavior of underlying {@link Object} methods wherever the
 * implementor deems it appropriate.
 *
 * <p>Some map operations which perform recursive traversal of the map may fail
 * with an exception for self-referential instances where the map directly or
 * indirectly contains itself. This includes the {@code clone()},
 * {@code equals()}, {@code hashCode()} and {@code toString()} methods.
 * Implementations may optionally handle the self-referential scenario, however
 * most current implementations do not do so.
 *
 * <p>This interface is a member of the
 * <a href="{@docRoot}/../technotes/guides/collections/index.html">
 * Java Collections Framework</a>.
 *
 * @param <K> the type of keys maintained by this map
 * @param <V> the type of mapped values
 * @author Josh Bloch
 * @see HashMap
 * @see TreeMap
 * @see Hashtable
 * @see SortedMap
 * @see Collection
 * @see Set
 * @since 1.2
 */
public interface Map<K, V> {
    // 查询操作

    /**
     * 获取键值对数量
     * 如果数量超过Integer.MAX_VALUE返回Integer.MAX_VALUE
     *
     * @return the number of key-value mappings in this map
     */
    int size();

    /**
     * 判断键值对是否为空
     *
     * @return <tt>true</tt> if this map contains no key-value mappings
     */
    boolean isEmpty();

    /**
     * 判断键值对是否包含指定键
     *
     * @param key 指定键
     * @return 是否包含指定键
     * @throws ClassCastException   指定键的类型和键值对键的类型不同
     * @throws NullPointerException 如果指定键为null并且键值对不能包含null
     */
    boolean containsKey(Object key);

    /**
     * 判断键值对是否包含指定值
     *
     * @param value 指定值
     * @return 是否包含指定值
     * @throws ClassCastException   指定值的类型和键值对值的类型不同
     * @throws NullPointerException 如果指定值为null并且键值对不能包含null
     */
    boolean containsValue(Object value);

    /**
     * 获取指定键的值
     *
     * @param key 指定键
     * @return 返回键值对中指定键的值或者当键值对不包含指定键返回为null
     * @throws ClassCastException   指定键的类型和键值对键的类型不同
     * @throws NullPointerException 如果指定建为null但是键值对不允许null值
     */
    V get(Object key);

    // 修改操作

    /**
     * 将指定的键值键入到键值对中，如果键已经存在只替换原来的值
     *
     * @param key   指定键
     * @param value v指定值
     * @return 获取指定键原始值，如果不存在则为null
     * @throws ClassCastException       键值对键或者值和指定的建或者值类型不同
     * @throws NullPointerException     指定的键或者值为null，但是键值对不允许null存在
     * @throws IllegalArgumentException if some property of the specified key
     *                                  or value prevents it from being stored in this map
     */
    V put(K key, V value);

    /**
     * 删除键值对重指定的键
     *
     * @param key 指定键
     * @return 被删除的值，如果指定键不存在则为null
     * @throws UnsupportedOperationException 不支持删除操作
     * @throws ClassCastException            指定键类型和键值对的键类型不一致
     * @throws NullPointerException          指定的键为null，但是键值对不允许null存在
     */
    V remove(Object key);


    // Bulk Operations

    /**
     * 将制定键值对中的全部元素添加到该键值对重
     *
     * @param m 指定键值对
     * @throws UnsupportedOperationException 如果不支持此操作
     * @throws ClassCastException            如果指定键值对和该键值对类型不匹配
     * @throws NullPointerException          指定键值对为null或者指定键值对中键或者值为null但是该键值对不允许null存在
     * @throws IllegalArgumentException      if some property of a key or value in
     *                                       the specified map prevents it from being stored in this map
     */
    void putAll(Map<? extends K, ? extends V> m);

    /**
     * 删除键值对全部键和值
     *
     * @throws UnsupportedOperationException 如果不支持此操作
     */
    void clear();


    // Views

    /**
     * 获取键值对中键的set对象
     *
     * @return a set view of the keys contained in this map
     */
    Set<K> keySet();

    /**
     * 获取指定键值对中值的结婚
     *
     * @return a collection view of the values contained in this map
     */
    Collection<V> values();

    /**
     * 获取键值对set对象
     *
     * @return a set view of the mappings contained in this map
     */
    Set<Map.Entry<K, V>> entrySet();

    /**
     * 键值对数据实现
     *
     * @see Map#entrySet()
     * @since 1.2
     */
    interface Entry<K, V> {
        /**
         * 获取键值对的键
         *
         * @return 键值对的键
         * @throws IllegalStateException implementations may, but are not
         *                               required to, throw this exception if the entry has been
         *                               removed from the backing map.
         */
        K getKey();

        /**
         * 获取键值对的值
         *
         * @return t键值对的值
         * @throws IllegalStateException implementations may, but are not
         *                               required to, throw this exception if the entry has been
         *                               removed from the backing map.
         */
        V getValue();

        /**
         * 设置键值对的值为指定值
         *
         * @param value 指定值
         * @return 键值对原来的值
         * @throws UnsupportedOperationException 如果键值对不支持put操作
         * @throws ClassCastException            如果指定值的类型和键值对值的类型不兼容
         * @throws NullPointerException          指定值为null键值对的值不允许为null
         * @throws IllegalArgumentException
         * @throws IllegalStateException
         */
        V setValue(V value);

        /**
         * 判断指定键值对和当前键值对是否相同
         * <p>
         * 重写equals
         *
         * @param o 指定键值对
         * @return <tt>true</tt> if the specified object is equal to this map
         * entry
         */
        boolean equals(Object o);

        /**
         * 重写键值对的hashcode
         *
         * @return the hash code value for this map entry
         * @see Object#hashCode()
         * @see Object#equals(Object)
         * @see #equals(Object)
         */
        int hashCode();

        /**
         * 按照键比较两个键值对
         *
         * @param <K> the {@link Comparable} type of then map keys
         * @param <V> the type of the map values
         * @return a comparator that compares {@link Map.Entry} in natural order on key.
         * @see Comparable
         * @since 1.8
         */
        public static <K extends Comparable<? super K>, V> Comparator<Map.Entry<K, V>> comparingByKey() {
            return (Comparator<Map.Entry<K, V>> & Serializable)
                    (c1, c2) -> c1.getKey().compareTo(c2.getKey());
        }

        /**
         * 按照值比较两个键值对
         *
         * @param <K> the type of the map keys
         * @param <V> the {@link Comparable} type of the map values
         * @return a comparator that compares {@link Map.Entry} in natural order on value.
         * @see Comparable
         * @since 1.8
         */
        public static <K, V extends Comparable<? super V>> Comparator<Map.Entry<K, V>> comparingByValue() {
            return (Comparator<Map.Entry<K, V>> & Serializable)
                    (c1, c2) -> c1.getValue().compareTo(c2.getValue());
        }

        /**
         * 根据指定的比较器按照键比较键值对
         *
         * @param <K> the type of the map keys
         * @param <V> the type of the map values
         * @param cmp 指定的比较器
         * @return a comparator that compares {@link Map.Entry} by the key.
         * @since 1.8
         */
        public static <K, V> Comparator<Map.Entry<K, V>> comparingByKey(Comparator<? super K> cmp) {
            Objects.requireNonNull(cmp);
            return (Comparator<Map.Entry<K, V>> & Serializable)
                    (c1, c2) -> cmp.compare(c1.getKey(), c2.getKey());
        }

        /**
         * 根据指定的比较器按照值比较键值对
         *
         * @param <K> the type of the map keys
         * @param <V> the type of the map values
         * @param cmp 指定的比较器
         * @return a comparator that compares {@link Map.Entry} by the value.
         * @since 1.8
         */
        public static <K, V> Comparator<Map.Entry<K, V>> comparingByValue(Comparator<? super V> cmp) {
            Objects.requireNonNull(cmp);
            return (Comparator<Map.Entry<K, V>> & Serializable)
                    (c1, c2) -> cmp.compare(c1.getValue(), c2.getValue());
        }
    }

    // 比较和hash

    /**
     * 判断两个键值对数组是否相同
     *
     * @param o object to be compared for equality with this map
     * @return <tt>true</tt> if the specified object is equal to this map
     */
    boolean equals(Object o);

    /**
     * 获取键值对数组的hash值
     *
     * @return the hash code value for this map
     * @see Map.Entry#hashCode()
     * @see Object#equals(Object)
     * @see #equals(Object)
     */
    int hashCode();

    // 默认方法

    /**
     * 回去指定键的值，获取不到时，返回默认值
     *
     * @param key          指定键
     * @param defaultValue 默认值
     * @throws ClassCastException   指定键的类型和键值对类型不一致
     * @throws NullPointerException 键值对不允许null但是指定键为null
     * @since 1.8
     */
    default V getOrDefault(Object key, V defaultValue) {
        V v;
        // 获取到的数据不为null或者包含数据 返回获取到的值， 否则就返回默认值
        return (((v = get(key)) != null) || containsKey(key))
                ? v
                : defaultValue;
    }

    /**
     * 循环执行指定操作
     *
     * @param action 指定操作
     * @throws NullPointerException            指定操作为null
     * @throws ConcurrentModificationException if an entry is found to be
     *                                         removed during iteration
     * @since 1.8
     */
    default void forEach(BiConsumer<? super K, ? super V> action) {
        // 检测动作不能为null
        Objects.requireNonNull(action);
        // 循环
        for (Map.Entry<K, V> entry : entrySet()) {
            K k;
            V v;
            try {
                // 获取数据
                k = entry.getKey();
                v = entry.getValue();
            } catch (IllegalStateException ise) {
                // this usually means the entry is no longer in the map.
                throw new ConcurrentModificationException(ise);
            }
            // 操作
            action.accept(k, v);
        }
    }

    /**
     * 对键值对数组指定指定的替换操作
     *
     * @param function 替换操作
     * @throws UnsupportedOperationException   键值对不支持set操作
     * @throws ClassCastException              替换值的类和键值对数组的类不兼容
     * @throws NullPointerException            替换动作为null,或者键值对不允许为null,替换后的值包含null
     * @throws IllegalArgumentException
     * @throws ConcurrentModificationException 字体替换期间数据被删除
     * @since 1.8
     */
    default void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
        // 替换操作不能为null
        Objects.requireNonNull(function);
        // 循环数据
        for (Map.Entry<K, V> entry : entrySet()) {
            K k;
            V v;
            try {
                // 获取键数据
                k = entry.getKey();
                v = entry.getValue();
            } catch (IllegalStateException ise) {
                // this usually means the entry is no longer in the map.
                // 如果获取不到数据抛出ConcurrentModificationException异常
                throw new ConcurrentModificationException(ise);
            }

            // ise thrown from function is not a cme.
            // 执行操作
            v = function.apply(k, v);

            try {
                // 重新设置值
                entry.setValue(v);
            } catch (IllegalStateException ise) {
                // this usually means the entry is no longer in the map.
                throw new ConcurrentModificationException(ise);
            }
        }
    }

    /**
     * 如果指定键存在且指定键的值不为null，不进行操作直接返回原来的值
     * 否则将新的数据将入到键值对数组中
     *
     * @param key   指定键
     * @param value 指定值
     * @return
     * @throws UnsupportedOperationException 如果键值对数组不支持put操作
     * @throws ClassCastException            指定键或者值和键值对数组不兼容
     * @throws NullPointerException          集合不允许null值，但是指定建或者值为null
     * @throws IllegalArgumentException      i
     * @since 1.8
     */
    default V putIfAbsent(K key, V value) {
        V v = get(key);
        if (v == null) {
            v = put(key, value);
        }

        return v;
    }

    /**
     * 删除指定键值对的值（键相同且值相同）
     *
     * @param key   指定键
     * @param value 指定值
     * @return 是否删除
     * @throws UnsupportedOperationException 键值对集合不支持删除操作
     * @throws ClassCastException            指定的键或者值和键值对集合的类型不兼容
     * @throws NullPointerException          指定键或者值为null 但是键值对集合不允许为null
     * @since 1.8
     */
    default boolean remove(Object key, Object value) {
        // 获取键值对的值
        Object curValue = get(key);
        // 如果键值对的值和指定的值不一致 或者不包含指定键 返回false
        if (!Objects.equals(curValue, value) ||
                (curValue == null && !containsKey(key))) {
            return false;
        }
        // 删除
        remove(key);
        return true;
    }

    /**
     * 替换指定键值对的值（键相同且值相同）
     *
     * @param key      指定的建
     * @param oldValue 原始值
     * @param newValue 新值
     * @return 是否替换成功
     * @throws UnsupportedOperationException 键值对数组不支持put操作
     * @throws ClassCastException            指定的键或者值与键值对数组的类型不兼容
     * @throws NullPointerException          指定键或者新的值为null 但是键值对集合不允许为null
     * @throws NullPointerException          原始的值为null 但是键值对集合不允许为null
     * @throws IllegalArgumentException
     * @since 1.8
     */
    default boolean replace(K key, V oldValue, V newValue) {
        // 获取原始值
        Object curValue = get(key);
        // 原始值和输入输入原始值不同 或者获取到的是null且集合不包含指定的键 返回false
        if (!Objects.equals(curValue, oldValue) ||
                (curValue == null && !containsKey(key))) {
            return false;
        }
        // 修改数据
        put(key, newValue);
        return true;
    }

    /**
     * 替换指定键的数据 如果不存在就返回null 存在返回被替换掉的值
     *
     * @param key   指定键
     * @param value 替换的值
     * @return 被替换掉的值 不存在的时候返回null
     * @throws UnsupportedOperationException 键值对集合不支持put操作
     * @throws ClassCastException            指定键或者值的类型和键值对数组的类型不兼容
     * @throws NullPointerException          指定键或者值为null 但是键值对集合不允许为null
     * @throws IllegalArgumentException
     * @since 1.8
     */
    default V replace(K key, V value) {
        V curValue;
        // 获取当前值不为null 或者包含当前的键
        if (((curValue = get(key)) != null) || containsKey(key)) {
            curValue = put(key, value);
        }
        return curValue;
    }

    /**
     *
     * 如果在键值对中不存在该键或者键存在的数据为null 进行替换操作
     *
     * @param key             指定键
     * @param mappingFunction 替换操作
     * @return 操作之后键对应的值
     * @throws NullPointerException          键值对集合不允许数组中的值为null但制定德键为null,或者替换操作为null
     * @throws UnsupportedOperationException 键值对集合不支持put操作
     * @throws ClassCastException            指定键或者值的类型和键值对数组的类型不兼容
     * @since 1.8
     */
    default V computeIfAbsent(K key,
                              Function<? super K, ? extends V> mappingFunction) {
        // 替换操作
        Objects.requireNonNull(mappingFunction);
        V v;
        if ((v = get(key)) == null) {
        // 原始值为null
            V newValue;
            // 计算新的值
            if ((newValue = mappingFunction.apply(key)) != null) {
                // 进行put操作
                put(key, newValue);
                return newValue;
            }
        }

        return v;
    }

    /**
     * 如果在键值对中存在该键且键存在的数据不为null 进行替换操作
     * 如果计算后的值为null 就删除键值对
     *
     * @param key               指定键
     * @param remappingFunction 替换操作
     * @return the new value associated with the specified key, or null if none
     * @throws NullPointerException           键值对集合不允许数组中的值为null但制定德键为null,或者替换操作为null
     * @throws UnsupportedOperationException 键值对集合不支持put操作
     * @throws ClassCastException            指定键或者值的类型和键值对数组的类型不兼容
     *
     * @since 1.8
     */
    default V computeIfPresent(K key,
                               BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
        Objects.requireNonNull(remappingFunction);
        V oldValue;
        // 获取并判断原始值不能为null
        if ((oldValue = get(key)) != null) {
            // 计算心智
            V newValue = remappingFunction.apply(key, oldValue);
            if (newValue != null) {
                // 新值不为null执行put操作
                put(key, newValue);
                return newValue;
            } else {
                // 新值为null执行remove操作
                remove(key);
                return null;
            }
        } else {
            return null;
        }
    }

    /**
     * 计算指定键的值
     *
     * @param key               指定键
     * @param remappingFunction 计算操作
     * @return the new value associated with the specified key, or null if none
     * @throws NullPointerException          如果键值对不允许为null但是指定的键为null或者计算操作为null
     * @throws UnsupportedOperationException 键值对数组不支持put操作
     * @throws ClassCastException            指定的键或者值和键值对数据的类型不兼容
     * @since 1.8
     */
    default V compute(K key,
                      BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
        Objects.requireNonNull(remappingFunction);
        // 获取原始值
        V oldValue = get(key);

        // 计算
        V newValue = remappingFunction.apply(key, oldValue);

        if (newValue == null) {
            // delete mapping
            if (oldValue != null || containsKey(key)) {
                // something to remove
                // 原始值存在，新值为null 删除key
                remove(key);
                return null;
            } else {
                // nothing to do. Leave things as they were.
                return null;
            }
        } else {
            // 新值不为null执行put操作
            // add or replace old mapping
            put(key, newValue);
            return newValue;
        }
    }

    /**
     * 合并指定键的数据
     *
     * @param key               指定键
     * @param value             非空合并值
     * @param remappingFunction 合并计算函数
     * @return 合并后指定键的值
     * @throws UnsupportedOperationException 如果键值对数组不支持put操作
     * @throws ClassCastException            指定的键或者值和键值对数据的类型不兼容
     * @throws NullPointerException          指定key为null或者指定值为null,或者操作为null
     * @since 1.8
     */
    default V merge(K key, V value,
                    BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
        // 合并操作不能为null
        Objects.requireNonNull(remappingFunction);
        // 合并值为null
        Objects.requireNonNull(value);
        // 原始值
        V oldValue = get(key);
        // 原始值为null直接将合并值作为合并后的值 否则指定合并操作获取合并后的
        V newValue = (oldValue == null) ? value :
                remappingFunction.apply(oldValue, value);
        if (newValue == null) {
            // 合并后的值为null 删除数据
            remove(key);
        } else {
            // 修改值
            put(key, newValue);
        }
        return newValue;
    }
}
